package com.yxy.aop;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.yxy.base.BusinessException;
import com.yxy.base.Pagingable;
import com.yxy.base.RestResponse;
import com.yxy.feign.VO.AdminUserInToken;
import com.yxy.model.SysLogs;
import com.yxy.service.SysLogsService;
import com.yxy.utils.PageDataList;
import com.yxy.utils.TokenCheckUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.RequestFacade;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.annotation.Resource;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Aspect
@Component
@Slf4j
public class LogAndExceptionAspect {
  @Value("${printRequest}")
  private String printRequest;//从配置文件中读取是否打印请求

  @Value("${printResponse}")//从配置文件中读取是否打印返回
  private String printResponse;

  @Resource
  private TokenCheckUtil tokenCheckUtil;


  @Resource
  private SysLogsService systemLogsService;

  //该切点定位到所有的处理http请求的controller方法
  @Pointcut("execution(public * com.yxy.controller.*.*(..))")
  public void webLog() {
  }

  @Around(value = "webLog()")
  public Object doAround(ProceedingJoinPoint joinPoint) {
    if (null == printRequest || "true".equals(printRequest)) {
      try {
        this.printRequestInfo(joinPoint);
      } catch (Exception ex) {
      }
    }
    //执行主代码逻辑
    RestResponse errResponse = new RestResponse(500, "");
    Object response = null;
    try {
      //检查token
      AdminUserInToken loginUser = tokenCheckUtil.getUserInfoByToken();
      RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
      requestAttributes.setAttribute("loginUser", loginUser, RequestAttributes.SCOPE_REQUEST);
      RequestContextHolder.setRequestAttributes(requestAttributes);
      //end
      //检查是否需要自动分页
      MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
      Method curMethod = methodSignature.getMethod();
      if (curMethod.isAnnotationPresent(Pagingable.class)) {//需要自动分页
        response = joinPoint.proceed();
        Page dbResultPage = (Page) (((RestResponse) response).getContent());
        List resultList = dbResultPage.getResult();

        PageDataList pageDataList = new PageDataList<>(dbResultPage.getTotal(),
                dbResultPage.getPages(),
                dbResultPage.getPageNum(), dbResultPage.getPageSize());
        pageDataList.setList(resultList);
        ((RestResponse) response).setContent(pageDataList);
      } else {
        response = joinPoint.proceed();
      }
      //end
    } catch (BusinessException ex) {
      log.error("", ex);
      errResponse.setStatus(ex.getCode());
      errResponse.setMessage(ex.getMsg());
      return errResponse;
    } catch (DuplicateKeyException ex) {
      log.error("", ex);
      errResponse.setMessage("该条目数据库中已经存在");
      return errResponse;
    } catch (RuntimeException ex) {
      log.error("", ex);
      errResponse.setMessage(ex.getMessage());
      return errResponse;
    } catch (Throwable ex) {
      log.error("", ex);
      errResponse.setMessage("服务器繁忙，请稍后再试");
      return errResponse;
    }
    if (printResponse != null && printResponse.equals("true")) {
      this.printResponseInfo(joinPoint, response);
    }
    return response;
  }

  /**
   * 前置日志，打印请求信息
   *
   * @param joinPoint
   */
  private void printRequestInfo(JoinPoint joinPoint) {
    StringBuffer params = new StringBuffer();
    if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
      for (int i = 0; i < joinPoint.getArgs().length; i++) {
        if (joinPoint.getArgs()[i] != null && joinPoint.getArgs()[i].getClass() != RequestFacade.class) {
          params.append(JSON.toJSONString(joinPoint.getArgs()[i]) + ";");
        }
      }
    }
    log.info("--请求id--：" + joinPoint.hashCode());
    log.info("--请求接口--：" + joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()");
    log.info("--请求参数--：" + params.toString());

    SysLogs systemLogs = new SysLogs();
    try {
      AdminUserInToken adminUser = tokenCheckUtil.getUserInfoByToken();
      String interfaceName = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()";
      if (interfaceName.contains("create") || interfaceName.contains("update")) {
        String hashCode = String.valueOf(joinPoint.hashCode());
        systemLogs.setHashCode(hashCode);
        systemLogs.setInterfaceName(joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()");
        systemLogs.setParams(params.toString());
        Set<Long> tenantIdList = adminUser.getTenantIdList();
        List<Long> result = new ArrayList<>(tenantIdList);
        Long tenantId = result.get(0);
        systemLogs.setTenantId(tenantId);
        try {
          systemLogsService.save(systemLogs);
        } catch (Exception e) {

        }
      }
    }catch (Exception e){

    }
  }

  /**
   * 打印接口返回结果
   *
   * @param joinPoint
   * @param res
   */
  private void printResponseInfo(JoinPoint joinPoint, Object res) {
    log.info("{}请求的返回结果为{}", joinPoint.hashCode(), JSON.toJSONString(res));
  }
}
